{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <div align=\"center\"> 梯度算法实现 </div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from sklearn.utils import shuffle\n",
    "import matplotlib.pyplot as plt\n",
    "from tensorflow.examples.tutorials.mnist import input_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(888)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 激活函数及导函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#####################################################################################\n",
    "# <codecell> activity function and derivative function\n",
    "#####################################################################################\n",
    "\n",
    "def sigmoid(x):\n",
    "    return 1 / (1 + np.exp(-1 * x))\n",
    "\n",
    "def d_sigmoid(x):\n",
    "    return sigmoid(x) * (1 - sigmoid(x))\n",
    "\n",
    "##\n",
    "\n",
    "def tanh(x):\n",
    "    return np.tanh(x)\n",
    "\n",
    "def d_tanh(x):\n",
    "    return 1 - np.tanh(x) ** 2\n",
    "\n",
    "##\n",
    "\n",
    "def relu(x):\n",
    "    mask = (x > 0.0) * 1.0\n",
    "    return x * mask\n",
    "\n",
    "def d_relu(x):\n",
    "    mask = (x > 0.0) * 1.0\n",
    "    return mask\n",
    "\n",
    "##\n",
    "\n",
    "def elu(matrix):\n",
    "    mask = (matrix <= 0) * 1.0\n",
    "    less_zero = matrix * mask\n",
    "    safe = (matrix > 0) * 1.0\n",
    "    greater_zero = matrix * safe\n",
    "    final = 3.0 * (np.exp(less_zero) - 1) * less_zero\n",
    "    return greater_zero + final\n",
    "\n",
    "def d_elu(matrix):\n",
    "    safe = (matrix > 0) * 1.0\n",
    "    mask2 = (matrix <= 0) * 1.0\n",
    "    temp = matrix * mask2\n",
    "    final = (3.0 * np.exp(temp))*mask2\n",
    "    return (matrix * safe) + final"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练数据及标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#####################################################################################\n",
    "# <codecell> train data\n",
    "#####################################################################################\n",
    "\n",
    "mnist = input_data.read_data_sets(\"/home/lidong/Datasets/ML/mnist\", one_hot=False)\n",
    "train = mnist.test\n",
    "images, labels = train.images, train.labels\n",
    "\n",
    "images.shape, labels.shape, labels[0:5]\n",
    "\n",
    "## select 0,1 labels and images\n",
    "\n",
    "zero_index, one_index = np.where(labels == 0)[0], np.where(labels == 1)[0]\n",
    "zero_image, one_image = images[[zero_index]], images[[one_index]]\n",
    "zero_label, one_label = np.expand_dims(labels[[zero_index]], axis=1), \\\n",
    "                        np.expand_dims(labels[[one_index]], axis=1)\n",
    "\n",
    "zero_image.shape, one_image.shape, zero_label.shape, one_label.shape\n",
    "\n",
    "## meld 0, 1 labels and images\n",
    "\n",
    "images_org = np.vstack((zero_image, one_image))\n",
    "labels_org = np.vstack((zero_label, one_label))\n",
    "images_org.shape, labels_org.shape, labels_org[2:5], labels[2:5]\n",
    "\n",
    "## shuffle method 1: sklearn.utils.shuffle\n",
    "\n",
    "images, labels = shuffle(images_org, labels_org)\n",
    "images.shape, labels.shape\n",
    "\n",
    "## shuffle method 2: np.random.shuffle\n",
    "\n",
    "# images_labels = np.hstack((images_org, labels_org))\n",
    "# np.random.shuffle(images_labels)\n",
    "# images, labels = images_labels[:, 0:-1], np.expand_dims(images_labels[:, -1], axis=1)\n",
    "# images.shape, labels.shape\n",
    "\n",
    "## train / test data\n",
    "\n",
    "train_num, test_num = 50, 20\n",
    "train_images, train_labels = images[0:train_num, :], labels[0:train_num, :]\n",
    "test_images, test_labels = images[-test_num-1:-1, :], labels[-test_num-1:-1, :]\n",
    "train_images.shape, test_images.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 算法模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Graph\n",
    "#####################################################################################\n",
    "#\n",
    "#      *****\n",
    "#      * x *                     elu\n",
    "#      *****               *****  l1A\n",
    "#                          *   *                     tanh\n",
    "#                          *****              *****   l2A\n",
    "#      *****                                  *   *\n",
    "#      *   *               *****              *****                   sigmoid\n",
    "#      *****               *   *                                 *****   l3A\n",
    "#              -------->   *****    -------->         -------->  *   *\n",
    "#        .                                      .                *****\n",
    "#             w1:784x256     .     w2:256x128   .     w3:128x1\n",
    "#        .                   .                  .\n",
    "#                            .\n",
    "#        .                                    *****\n",
    "#                          *****              *   *\n",
    "#                          *   *              *****\n",
    "#      *****               *****\n",
    "#      *   *\n",
    "#      *****\n",
    "#      1x784               1x256               1x128               1x1\n",
    "#      input              layer-1             layer-2            layer-3\n",
    "#\n",
    "# 损失函数:\n",
    "#\n",
    "#        (sigmoid(w3 * tanh(w2 * elu(w1 * x))) - label)^2 * 0.2\n",
    "#           |     |     |   |     |  ------ x d(w1)\n",
    "#           |     |     |   |     |    l1\n",
    "#           |     |     |   |     +-------- d_elu(l1) d(l1)\n",
    "#           |     |     |   |       l1A\n",
    "#           |     |     |   +-------------- l1A d(w2)\n",
    "#           |     |     |         l2\n",
    "#           |     |     +------------------ d_tanh(l2) d(l2)\n",
    "#           |     |            l2A\n",
    "#           |     +------------------------ l2A d_sigmoid(l3) (l3A - label) d(w3) |\n",
    "#           |               l3                                                    |\n",
    "#           +------------------------------     d_sigmoid(l3) (l3A - label) d(l3) |w3\n",
    "#                       l3A                                                       |\n",
    "#         --------------------------------------------------- (l3A - label) d(l3A)|\n",
    "#                                cost\n",
    "#\n",
    "#\n",
    "# 0-9数字图像只选取了0和1, 所以简化模型, 采用全连接, 加最后一层的sigmoid,而不是softmax\n",
    "# 矩阵求导是个难点, 需要基本的了解, 否则代码是很难理解, 什么时候转置, 什么时候点乘等."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 全局参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Global param\n",
    "#####################################################################################\n",
    "\n",
    "## weight\n",
    "\n",
    "_w1 = np.random.randn(784, 256) * 0.2\n",
    "_w2 = np.random.randn(256, 128) * 0.2\n",
    "_w3 = np.random.randn(128, 1) * 0.2\n",
    "\n",
    "## hyper parameters\n",
    "\n",
    "learn_rate = 0.0003\n",
    "num_epoch = 100\n",
    "cost_array = {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SGD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SGD current Iter:  0  Total Cost:  6.536087150676306\n",
      "SGD current Iter:  10  Total Cost:  4.7039394768622405\n",
      "SGD current Iter:  20  Total Cost:  3.5608437208651247\n",
      "SGD current Iter:  30  Total Cost:  2.8194669282531857\n",
      "SGD current Iter:  40  Total Cost:  2.2232067357410785\n",
      "SGD current Iter:  50  Total Cost:  1.773685538844725\n",
      "SGD current Iter:  60  Total Cost:  1.4414821409916552\n",
      "SGD current Iter:  70  Total Cost:  1.1979211742848752\n",
      "SGD current Iter:  80  Total Cost:  1.0160552400127763\n",
      "SGD current Iter:  90  Total Cost:  0.8750329832254002\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> SGD\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        # layer1\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        # layer2\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        # layer3\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        # loss\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        # eval gradient\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)   # 128x1\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)   # 256x128\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)   # 784x256\n",
    "\n",
    "        # update weight\n",
    "        w3 = w3 - learn_rate * g3\n",
    "        w2 = w2 - learn_rate * g2\n",
    "        w1 = w1 - learn_rate * g1\n",
    "\n",
    "    if iter % 10 == 0:\n",
    "        print(\"SGD current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['sgd'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Momentum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Momentum current Iter:  0  Total Cost:  6.5360282734808886\n",
      "Momentum current Iter:  10  Total Cost:  4.702489119548017\n",
      "Momentum current Iter:  20  Total Cost:  3.559091644015248\n",
      "Momentum current Iter:  30  Total Cost:  2.8175599262177844\n",
      "Momentum current Iter:  40  Total Cost:  2.2210946534889504\n",
      "Momentum current Iter:  50  Total Cost:  1.7716465695323558\n",
      "Momentum current Iter:  60  Total Cost:  1.4398028082048022\n",
      "Momentum current Iter:  70  Total Cost:  1.1965104244750853\n",
      "Momentum current Iter:  80  Total Cost:  1.0148164340525612\n",
      "Momentum current Iter:  90  Total Cost:  0.8739691541636565\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Momentum\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "v1, v2, v3 = 0, 0, 0\n",
    "alpha = 0.001\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        v3 = v3 * alpha + learn_rate * g3\n",
    "        v2 = v2 * alpha + learn_rate * g2\n",
    "        v1 = v1 * alpha + learn_rate * g1\n",
    "\n",
    "        w3 = w3 - v3\n",
    "        w2 = w2 - v2\n",
    "        w1 = w1 - v1\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Momentum current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['Momentum'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NAG"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nesterov accelerated gradient current Iter:  0  Total Cost:  6.536028295188458\n",
      "Nesterov accelerated gradient current Iter:  10  Total Cost:  4.7024892734738035\n",
      "Nesterov accelerated gradient current Iter:  20  Total Cost:  3.5590915657097213\n",
      "Nesterov accelerated gradient current Iter:  30  Total Cost:  2.817559539393665\n",
      "Nesterov accelerated gradient current Iter:  40  Total Cost:  2.2210936943521706\n",
      "Nesterov accelerated gradient current Iter:  50  Total Cost:  1.7716457247952035\n",
      "Nesterov accelerated gradient current Iter:  60  Total Cost:  1.4398017094252133\n",
      "Nesterov accelerated gradient current Iter:  70  Total Cost:  1.1965087859645642\n",
      "Nesterov accelerated gradient current Iter:  80  Total Cost:  1.0148145176892138\n",
      "Nesterov accelerated gradient current Iter:  90  Total Cost:  0.8739675344007252\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> NAG: Nesterov accelerated gradient\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "v1, v2, v3 = 0, 0, 0\n",
    "alpha = 0.001\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        # 预知的能力, 提前使用动量的信息, 然后预知下一时刻的梯度\n",
    "        fake_w3 = w3 - alpha * v3\n",
    "        fake_w2 = w2 - alpha * v2\n",
    "        fake_w1 = w1 - alpha * v1\n",
    "\n",
    "        l1 = image.dot(fake_w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(fake_w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(fake_w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3_fake = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(fake_w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2_fake = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(fake_w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1_fake = g13.T.dot(g11 * g12)\n",
    "\n",
    "        v3 = v3 * alpha + learn_rate * g3_fake\n",
    "        v2 = v2 * alpha + learn_rate * g2_fake\n",
    "        v1 = v1 * alpha + learn_rate * g1_fake\n",
    "\n",
    "        w3 = w3 - v3\n",
    "        w2 = w2 - v2\n",
    "        w1 = w1 - v1\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Nesterov accelerated gradient current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['NAG'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adagrad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adagrad current Iter:  0  Total Cost:  6.666279980434833\n",
      "Adagrad current Iter:  10  Total Cost:  5.938413756637069\n",
      "Adagrad current Iter:  20  Total Cost:  5.5551501935017376\n",
      "Adagrad current Iter:  30  Total Cost:  5.362340744469407\n",
      "Adagrad current Iter:  40  Total Cost:  5.20170269514624\n",
      "Adagrad current Iter:  50  Total Cost:  4.994427581189343\n",
      "Adagrad current Iter:  60  Total Cost:  4.849805978705678\n",
      "Adagrad current Iter:  70  Total Cost:  4.813890657118094\n",
      "Adagrad current Iter:  80  Total Cost:  4.8387691617087905\n",
      "Adagrad current Iter:  90  Total Cost:  4.888179423498649\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Adagrad\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "vlr_1, vlr_2, vlr_3 = 0, 0, 0\n",
    "epsilon = 0.00000001\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        # 累加梯度平方, 自适应\n",
    "        vlr_3 = vlr_3 + g3 ** 2  # 128x1\n",
    "        vlr_2 = vlr_2 + g2 ** 2  # 256x128\n",
    "        vlr_1 = vlr_1 + g1 ** 2  # 784x256\n",
    "\n",
    "        w3 = w3 - (learn_rate / np.sqrt(vlr_3 + epsilon)) * g3\n",
    "        w2 = w2 - (learn_rate / np.sqrt(vlr_2 + epsilon)) * g2\n",
    "        w1 = w1 - (learn_rate / np.sqrt(vlr_1 + epsilon)) * g1\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Adagrad current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "\n",
    "cost_array['Adagrad'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adadelta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adadelta current Iter:  0  Total Cost:  5.555458382436835\n",
      "Adadelta current Iter:  10  Total Cost:  0.4173872280606051\n",
      "Adadelta current Iter:  20  Total Cost:  0.015685602889927472\n",
      "Adadelta current Iter:  30  Total Cost:  0.0004999529952571813\n",
      "Adadelta current Iter:  40  Total Cost:  0.0003014010172245164\n",
      "Adadelta current Iter:  50  Total Cost:  0.00021961229959164516\n",
      "Adadelta current Iter:  60  Total Cost:  0.00017429757669405315\n",
      "Adadelta current Iter:  70  Total Cost:  0.0001455897805569645\n",
      "Adadelta current Iter:  80  Total Cost:  0.0001257113900228519\n",
      "Adadelta current Iter:  90  Total Cost:  0.00011102101372915368\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Adadelta\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "epsilon, gamma = 0.000001, 0.001\n",
    "vlr_1, vlr_2, vlr_3 = 0, 0, 0\n",
    "wlr_1, wlr_2, wlr_3 = 0, 0, 0\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        # 梯度平方和衰减平均\n",
    "        vlr_3 = gamma * vlr_3 + (1-gamma) * g3 ** 2\n",
    "        vlr_2 = gamma * vlr_2 + (1-gamma) * g2 ** 2\n",
    "        vlr_1 = gamma * vlr_1 + (1-gamma) * g1 ** 2\n",
    "\n",
    "        delta_3 = - (np.sqrt(wlr_3 + epsilon) / np.sqrt(vlr_3 + epsilon)) * g3\n",
    "        delta_2 = - (np.sqrt(wlr_2 + epsilon) / np.sqrt(vlr_2 + epsilon)) * g2\n",
    "        delta_1 = - (np.sqrt(wlr_1 + epsilon) / np.sqrt(vlr_1 + epsilon)) * g1\n",
    "\n",
    "        # Delta权重平方和衰减平均\n",
    "        wlr_3 = gamma * wlr_3 + (1-gamma) * delta_3 ** 2\n",
    "        wlr_2 = gamma * wlr_2 + (1-gamma) * delta_2 ** 2\n",
    "        wlr_1 = gamma * wlr_1 + (1-gamma) * delta_1 ** 2\n",
    "\n",
    "        w3 = w3 + delta_3\n",
    "        w2 = w2 + delta_2\n",
    "        w1 = w1 + delta_1\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Adadelta current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['Adadelta'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RMSprop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RMSprop current Iter:  0  Total Cost:  6.662123251715308\n",
      "RMSprop current Iter:  10  Total Cost:  6.0221590057746495\n",
      "RMSprop current Iter:  20  Total Cost:  0.18023272092255807\n",
      "RMSprop current Iter:  30  Total Cost:  0.0008802990872975141\n",
      "RMSprop current Iter:  40  Total Cost:  0.00024211243160348058\n",
      "RMSprop current Iter:  50  Total Cost:  0.00014384174440690018\n",
      "RMSprop current Iter:  60  Total Cost:  0.00010473995056811312\n",
      "RMSprop current Iter:  70  Total Cost:  8.26706148535364e-05\n",
      "RMSprop current Iter:  80  Total Cost:  6.840295279388158e-05\n",
      "RMSprop current Iter:  90  Total Cost:  5.839048601164011e-05\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> RMSprop: 是Adadelta一个特殊情况\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "epsilon, gamma = 0.00000001, 0.9\n",
    "vlr_1, vlr_2, vlr_3 = 0, 0, 0\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        vlr_3 = gamma * vlr_3 + (1 - gamma) * g3 ** 2\n",
    "        vlr_2 = gamma * vlr_2 + (1 - gamma) * g2 ** 2\n",
    "        vlr_1 = gamma * vlr_1 + (1 - gamma) * g1 ** 2\n",
    "\n",
    "        w3 = w3 - (learn_rate/np.sqrt(vlr_3 + epsilon)) * g3\n",
    "        w2 = w2 - (learn_rate/np.sqrt(vlr_2 + epsilon)) * g2\n",
    "        w1 = w1 - (learn_rate/np.sqrt(vlr_1 + epsilon)) * g1\n",
    "    if iter % 10 == 0:\n",
    "        print(\"RMSprop current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['RMSprop'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adam"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adam current Iter:  0  Total Cost:  5.640137434732136\n",
      "Adam current Iter:  10  Total Cost:  2.392271710256568\n",
      "Adam current Iter:  20  Total Cost:  0.4739090894708882\n",
      "Adam current Iter:  30  Total Cost:  0.18447750680346103\n",
      "Adam current Iter:  40  Total Cost:  0.06851363326585835\n",
      "Adam current Iter:  50  Total Cost:  0.0416372969439648\n",
      "Adam current Iter:  60  Total Cost:  0.026212537209548022\n",
      "Adam current Iter:  70  Total Cost:  0.01764994299786532\n",
      "Adam current Iter:  80  Total Cost:  0.012945100492132884\n",
      "Adam current Iter:  90  Total Cost:  0.009185203318895196\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Adam (自适应矩估计, 一阶均值, 二阶方差(非中心)\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "epsilon, beta_1, beta_2 = 0.00000001, 0.9, 0.999\n",
    "mlr_1, mlr_2, mlr_3 = 0, 0, 0\n",
    "vlr_1, vlr_2, vlr_3 = 0, 0, 0\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        # 一阶mean: 梯度衰减均值\n",
    "        mlr_3 = beta_1 * mlr_3 + (1 - beta_1) * g3\n",
    "        mlr_2 = beta_1 * mlr_2 + (1 - beta_1) * g2\n",
    "        mlr_1 = beta_1 * mlr_1 + (1 - beta_1) * g1\n",
    "\n",
    "        # 二阶variance: 梯度指数衰减(梯度平方衰减均值)\n",
    "        vlr_3 = beta_2 * vlr_3 + (1 - beta_2) * g3 ** 2\n",
    "        vlr_2 = beta_2 * vlr_2 + (1 - beta_2) * g2 ** 2\n",
    "        vlr_1 = beta_2 * vlr_1 + (1 - beta_2) * g1 ** 2\n",
    "\n",
    "        # 矫正\n",
    "        mlr_3_hat = mlr_3 / (1 - beta_1)\n",
    "        mlr_2_hat = mlr_2 / (1 - beta_1)\n",
    "        mlr_1_hat = mlr_1 / (1 - beta_1)\n",
    "\n",
    "        vlr_3_hat = vlr_3 / (1 - beta_2)\n",
    "        vlr_2_hat = vlr_2 / (1 - beta_2)\n",
    "        vlr_1_hat = vlr_1 / (1 - beta_2)\n",
    "\n",
    "        w3 = w3 - (learn_rate / (np.sqrt(vlr_3_hat) + epsilon)) * mlr_3_hat\n",
    "        w2 = w2 - (learn_rate / (np.sqrt(vlr_2_hat) + epsilon)) * mlr_2_hat\n",
    "        w1 = w1 - (learn_rate / (np.sqrt(vlr_1_hat) + epsilon)) * mlr_1_hat\n",
    "\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Adam current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['Adam'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Nadam"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nadam current Iter:  0  Total Cost:  5.683507533833745\n",
      "Nadam current Iter:  10  Total Cost:  2.5065008758041527\n",
      "Nadam current Iter:  20  Total Cost:  0.33268948826621214\n",
      "Nadam current Iter:  30  Total Cost:  0.12755957942989032\n",
      "Nadam current Iter:  40  Total Cost:  0.06942463072059477\n",
      "Nadam current Iter:  50  Total Cost:  0.042654097292935206\n",
      "Nadam current Iter:  60  Total Cost:  0.03002246915358719\n",
      "Nadam current Iter:  70  Total Cost:  0.01976767512075325\n",
      "Nadam current Iter:  80  Total Cost:  0.012825742523476345\n",
      "Nadam current Iter:  90  Total Cost:  0.009174874285437812\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Nadam (incorporate NAG into Adam)\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "epsilon, beta_1, beta_2 = 0.00000001, 0.9, 0.999\n",
    "\n",
    "mlr_1, mlr_2, mlr_3 = 0, 0, 0\n",
    "vlr_1, vlr_2, vlr_3 = 0, 0, 0\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "        image = np.expand_dims(train_images[index], axis=0)\n",
    "        label = np.expand_dims(train_labels[index], axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        mlr_3 = beta_1 * mlr_3 + (1 - beta_1) * g3\n",
    "        mlr_2 = beta_1 * mlr_2 + (1 - beta_1) * g2\n",
    "        mlr_1 = beta_1 * mlr_1 + (1 - beta_1) * g1\n",
    "\n",
    "        vlr_3 = beta_2 * vlr_3 + (1 - beta_2) * g3 ** 2\n",
    "        vlr_2 = beta_2 * vlr_2 + (1 - beta_2) * g2 ** 2\n",
    "        vlr_1 = beta_2 * vlr_1 + (1 - beta_2) * g1 ** 2\n",
    "\n",
    "        mlr_3_hat = mlr_3 / (1 - beta_1)\n",
    "        mlr_2_hat = mlr_2 / (1 - beta_1)\n",
    "        mlr_1_hat = mlr_1 / (1 - beta_1)\n",
    "\n",
    "        vlr_3_hat = vlr_3 / (1 - beta_2)\n",
    "        vlr_2_hat = vlr_2 / (1 - beta_2)\n",
    "        vlr_1_hat = vlr_1 / (1 - beta_2)\n",
    "\n",
    "        w3 = w3 - (learn_rate/(np.sqrt(vlr_3_hat) + epsilon)) * \\\n",
    "                    (beta_1 * mlr_3_hat + (((1 - beta_1) * g3) / (1 - beta_1)))\n",
    "        w2 = w2 - (learn_rate/(np.sqrt(vlr_2_hat) + epsilon)) * \\\n",
    "                    (beta_1 * mlr_2_hat + (((1 - beta_1) * g2) / (1 - beta_1)))\n",
    "        w1 = w1 - (learn_rate/(np.sqrt(vlr_1_hat) + epsilon)) * \\\n",
    "                    (beta_1 * mlr_1_hat + (((1 - beta_1) * g1) / (1 - beta_1)))\n",
    "    if iter % 10 == 0:\n",
    "        print(\"Nadam current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['Nadam'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SGD with Gaussian Noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SGD with Gaussian Noise current Iter:  0  Total Cost:  6.536011294865201\n",
      "SGD with Gaussian Noise current Iter:  10  Total Cost:  4.703792555740373\n",
      "SGD with Gaussian Noise current Iter:  20  Total Cost:  3.5607525365811683\n",
      "SGD with Gaussian Noise current Iter:  30  Total Cost:  2.8194896592760905\n",
      "SGD with Gaussian Noise current Iter:  40  Total Cost:  2.223787791423323\n",
      "SGD with Gaussian Noise current Iter:  50  Total Cost:  1.7739982937232945\n",
      "SGD with Gaussian Noise current Iter:  60  Total Cost:  1.4419054404573248\n",
      "SGD with Gaussian Noise current Iter:  70  Total Cost:  1.1983793067180164\n",
      "SGD with Gaussian Noise current Iter:  80  Total Cost:  1.0165376507715156\n",
      "SGD with Gaussian Noise current Iter:  90  Total Cost:  0.8754741487107224\n"
     ]
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> SGD with Gaussian Noise\n",
    "#####################################################################################\n",
    "\n",
    "w1, w2, w3 = _w1, _w2, _w3\n",
    "\n",
    "eta = 0.001\n",
    "\n",
    "cost_temp_array = []\n",
    "for iter in range(num_epoch):\n",
    "    total_cost = 0\n",
    "    for index in range(len(train_images)):\n",
    "\n",
    "        image = np.expand_dims(train_images[index],axis=0)\n",
    "        label = np.expand_dims(train_labels[index],axis=1)\n",
    "\n",
    "        l1 = image.dot(w1)\n",
    "        l1A = elu(l1)\n",
    "\n",
    "        l2 = l1A.dot(w2)\n",
    "        l2A = tanh(l2)\n",
    "\n",
    "        l3 = l2A.dot(w3)\n",
    "        l3A = sigmoid(l3)\n",
    "\n",
    "        total_cost += np.square(l3A - label).sum() * 0.5\n",
    "\n",
    "        g31 = l3A - label\n",
    "        g32 = d_sigmoid(l3)\n",
    "        g33 = l2A\n",
    "        g3 = g33.T.dot(g31 * g32)\n",
    "\n",
    "        g21 = (g31 * g32).dot(w3.T)\n",
    "        g22 = d_tanh(l2)\n",
    "        g23 = l1A\n",
    "        g2 = g23.T.dot(g21 * g22)\n",
    "\n",
    "        g11 = (g21 * g22).dot(w2.T)\n",
    "        g12 = d_elu(l1)\n",
    "        g13 = image\n",
    "        g1 = g13.T.dot(g11 * g12)\n",
    "\n",
    "        noise = np.random.normal(loc=0, scale=eta / (np.power((1 + iter), 0.55)))\n",
    "\n",
    "        w3 = w3 - learn_rate * (g3 + noise)\n",
    "        w2 = w2 - learn_rate * (g2 + noise)\n",
    "        w1 = w1 - learn_rate * (g1 + noise)\n",
    "    if iter % 10 == 0:\n",
    "        print(\"SGD with Gaussian Noise current Iter: \", iter, \" Total Cost: \", total_cost)\n",
    "    cost_temp_array.append(total_cost)\n",
    "cost_array['SGDGN'] = cost_temp_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 绘制算法比较图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7fb4c98ec668>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#####################################################################################\n",
    "# <codecell> Plot\n",
    "#####################################################################################\n",
    "\n",
    "colors = ['r', 'g', 'b', 'c', 'k', 'y', 'm', 'gold', 'peru']\n",
    "\n",
    "for i, (name, costs) in enumerate(cost_array.items()):\n",
    "    plt.plot(np.arange(num_epoch), costs,\n",
    "            color=colors[i], linewidth=3, label=name)\n",
    "plt.title(\"Total Cost per Training\")\n",
    "plt.legend()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
